package j2EE.servlet;

import lombok.extern.log4j.Log4j2;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;

/**
 * Created with Intel IDEA.
 * 缓存过滤器
 * @Auther: gjt
 * @Date: 2024/11/30 15:01
 */
@Log4j2
public class CacheFilter implements Filter {

    private FilterConfig filterConfig;


    /**
     * 没有使用静态，根据过滤器规范，只会为部署描述文件中的每一个过滤器元素产生一个过滤器实例。因而我们可以在每个过滤器中保留单独的缓存，允许过滤器
     * 链中的不同点上有多个缓存，而不用担心把相同的数据散列到多个缓存对象上。
     * 汽车的不同配置是可以缓存的，用户的信用卡信息是不能缓存的。
     */
    // 数据缓存
    private HashMap cache;
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // 缓存键为 URI + 查询串
        String key = req.getRequestURI() + "?" + req.getQueryString();
        // 仅缓存包含可缓存数据的get请求
        if(req.getMethod().equalsIgnoreCase("get") && isCacheable(key)){
            //查找cache 中的数据
            byte[] data = (byte[])cache.getOrDefault(key,null);

            // 缓存失败时生成通用结果并添加缓存
            if(null == data){
                CacheResponseWrapper crw = new CacheResponseWrapper(resp);
                filterChain.doFilter(req , crw);
                data = crw.getByte();
                cache.put(key,data);
            }

            // 如果再缓存中找到或则添加至缓存，从缓存中生生结果
            if(null != data){
                resp.setContentType("text/html");
                resp.setContentLength(data.length);
                try {
                    OutputStream outputStream = resp.getOutputStream();

                    outputStream.write(data);
                    outputStream.close();
                    return;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        // 如果数据不可缓存或缓存因为别的原因失败，则生成通用数据
        filterChain.doFilter(req,resp);
    }

    private boolean isCacheable(String key){
        if(cache.containsKey(key)){
            log.info("此内容已经再缓存中请在缓存中拿去!");
            return true;
        }else {
            log.info("此内容没有在缓存中!");
            return false;
        }
    }

    // 初始化缓存
    public void init(FilterConfig filterConfig){
        this.filterConfig = filterConfig;
        cache = new HashMap();
    }
}
